import GCGlobal from "../GCGlobal";
import GCResponse, { GCEmptyResponse } from "./GCResponse";

export enum ErrorCode {
    SUCCEED = 0,
    ERROR = 1,
    TIMEOUT = 2,
    PARSE_ERROR = 3,
    WRONG_CODE = 4,
}

export default class GCNetwork {

    private static _url: string = '';

    public static initNetwork() {
        const paramsObj = GCGlobal.getParamsObj();
        // 默认使用远程服务器。除非在地址中指定了host参数
        let url = '';

        const host = paramsObj['host'];
        if (host) {
            url = host;
        } else {
            url = 'https://canace.club';
        }

        this._url = url;

        cc.log(`initNetwork.url: ${url}`);
    }

    public static getUrl() {
        return this._url;
    }

    public static GET(url: string, params: Object, ResponseClass?: typeof GCResponse) {
        url = this._url + `/${url}`;

        return this.doRequest('GET', {
            url: url,
            payload: params,
            ResponseClass
        });
    }

    public static async POST<T extends GCResponse>(url: string, payload: Object, ResponseClass?: typeof GCResponse): Promise<T> {
        url = this._url + `/${url}`;
        return this.doRequest('POST', { url, payload, ResponseClass }) as any;
    }

    private static async doRequest(
        method: 'GET' | 'POST',
        options: {
            url: string,
            header?: Object,
            payload?: Object,
            ResponseClass?: typeof GCResponse
        }) {

        return new Promise((resolve, reject) => {
            this.request(
                method,
                options,
                (_code: number, _resp: Object) => {

                    if (_code === ErrorCode.SUCCEED) {
                        resolve(_resp);
                    } else {
                        reject(_code);
                    }
                }
            );
        })

    }

    private static request(
        method: 'GET' | 'POST', options: {
            url: string,
            header?: Object,
            payload?: Object,
            ResponseClass?: typeof GCResponse
        },
        cb: (code: number, resp: any) => void) {

        const xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            if (this.readyState == 4) {
                if (this.status >= 200 && this.status < 300) {
                    console.log(this.response);

                    try {
                        const payload = JSON.parse(this.response);

                        const cls = options.ResponseClass || GCEmptyResponse;
                        try {
                            let resp = new cls();
                            resp.parseResponse(payload);

                            cb(ErrorCode.SUCCEED, resp);

                        } catch (e2) {
                            cb(ErrorCode.PARSE_ERROR, null);
                        }

                    } catch (e) {
                        cb(ErrorCode.PARSE_ERROR, null);
                    }
                } else {
                    try {
                        const err = JSON.parse(this.response);
                        cc.log(err);
                        cb(err, null);
                    } catch (e) {
                        cb(ErrorCode.PARSE_ERROR, null);
                        return;
                    }
                }
            }
        }

        xhr.onerror = function () {
            cc.error('onerror');
            cb(ErrorCode.ERROR, null);
        };

        xhr.ontimeout = function () {
            cb(ErrorCode.TIMEOUT, null);
        };

        let url = new URL(options.url);
        if (method == 'GET') {
            if (options.payload) {
                for (let key in options.payload) {
                    url.searchParams.set(key, options.payload[key]);
                }
            }
        }

        if (options.header) {
            for (let key in options.header) {
                xhr.setRequestHeader(key, options.header[key]);
            }
        }

        xhr.timeout = 10 * 1000;

        xhr.open(method, url)

        const token = GCGlobal.token;
        if (token) {
            Object.assign(options.payload, { token });
        }

        xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
        if (method == 'POST') {
            xhr.send(JSON.stringify(options.payload || {}));
        } else {
            xhr.send()
        }

        cc.log(`Network.request${method}, url: ${url.toString()} `);
    }
}

if (CC_DEBUG) {
    (window as any).Network = GCNetwork;
}
